package ru.dcsearch.indexer;

/***************************************************************************
 *   Modified by TMC
 *   berechitai@gmail.com
 *
 *   This file is part of DC Indexer project
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 ***************************************************************************/
/*
 *  Mobile DC - a DirectConnect client written in Java and designed for
 *  the Sony Ericsson p800/p900 or equivalent Symbian OS 7.0 platforms
 *  Copyright (C) 2004 Conrad Helgesson, vakum@home.se
 *
 *  Mobile DC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Mobile DC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Mobile DC; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


import java.util.Hashtable;
import java.util.Set;
import java.util.Iterator;
import java.io.IOException;

// This class works tight with ClientConnection.
public class ClientConnectionManager
{
	//::Class-related
	private DCClient mw;
	private Hashtable<Integer, ClientConnection> Connections = new Hashtable<Integer, ClientConnection>(); //(ccID, ClientConnection())
    private Hashtable<Integer, ConnectionInfo> ConnectionInfos = new Hashtable<Integer, ConnectionInfo>(); //(ccID, ClientConnection())


	//::Static data
	public final static int Unknown	= 0;
	public final static int Download	= 1;
	public final static int Upload	= 2;

	public final static int DLing = 0;
	public final static int ULing = 1;
	public final static int DLoad = 2;
	public final static int ULoad = 3;
	public final static int Not_C = 4;
	public final static int C_ing = 5;
	public final static int Abort = 6;
	public final static int Waita = 7;
	public final static int Finit = 8;
	public final static int RSing = 9;



	//::A space to store passive download data. (String Nick, String file)
	public Hashtable<Object, Object> RevConnectDLlist = new Hashtable<Object, Object>();

	//::Data
	private int ccIDcount = 0;
	public  int slotstaken = 0;
	private long lastUpdated = System.currentTimeMillis();




    class ConnectionInfo {

            public int			CCDirection = 0;
            public int			CClistIndex = 0;
            public int			CCport = 0;
            public String		CCip = "";
            public String		CCnick = "";
            public String		CCfile = "";
            public String		CCinfo = "";
            public long		    CCbps = 0;
            public long		    CCmaxbytes = 0;
            public long		    CCbytes = 0;
            public int			CCstate = 0;
            public long		    lastBytesReceived = 0;


    }


	//::Main
	public ClientConnectionManager(DCClient w) { mw = w; }

	public void NewCC(String nick, String ip, String file, int direction) throws IOException
	{
        //Get free port
        int port =  mw.pp.lockPort();
        if (port == 0) {

            throw new IOException("Can not lock port");
        }


        mw.nw.sendCommand("$ConnectToMe", nick +" "+ mw.p.getMyIp() +":"+port);


        ConnectionInfo info = new ConnectionInfo();
		//Add new download to download list
		Logger.printLog("CLIENT: Creating new...");
		//Add info to this Client Connection ID.
			 info.CCnick = nick;
			   info.CCip = ip;
			 info.CCfile = file;
			 info.CCport = port;
		info.CCDirection = direction;
		info.CClistIndex = ccIDcount;
		     info.CCinfo = "Opening Connection...";
			info.CCbytes = 0;
			info.CCstate = port;
		 info.CCmaxbytes = 1;
		      info.CCbps = 0;
  info.lastBytesReceived = 0;

  		//tart new connection tread
		Connections.put(ccIDcount, new ClientConnection(this, mw, ccIDcount, ip.equals(""), port));
        ConnectionInfos.put(ccIDcount, info);
		ccIDcount += 1;
	}


	public void CloseCC(int index)
	{
		//Disconnect download

           Connections.get(index).disconnect();
	}


	public void RemoveCC(int index)
	{
		//Remove download from list
		Logger.printLog("remove listindex "+index);


				Connections.get(index).disconnect();
				//remove all data as well.
				Connections.remove(index);
				ConnectionInfos.remove(index);
	}


    public int getNumberActiveConnections() {

        return Connections.size();
    }

	public void CalculateBPS()
	{
		//Calculate download speed Bps
		long time = System.currentTimeMillis();
        Set<Integer> set = ConnectionInfos.keySet();

        for (Integer aSet : set) {
            ConnectionInfo info = ConnectionInfos.get(aSet);
            if (info.CCstate < 2) {
                info.CCbps = (((((info.CCbytes - info.lastBytesReceived) + 1) * 1000) / (time - lastUpdated)) + info.CCbps) / 2;
                info.lastBytesReceived = info.CCbytes;
            }
        }

		lastUpdated = time;
	}


	//::Useful data which other classes can get:
	public String getNick(int ccID) { return ConnectionInfos.get(ccID).CCnick; }
	public String getFile(int ccID) { return ConnectionInfos.get(ccID).CCfile; }
	public String getIP(int ccID) { return ConnectionInfos.get(ccID).CCip; }
	public int getPort(int ccID) { return ConnectionInfos.get(ccID).CCport; }
	public int getDirection(int ccID) { return ConnectionInfos.get(ccID).CCDirection; }
	public int getlistIndex(int ccID) { return ConnectionInfos.get(ccID).CClistIndex; }
	public long getMaxBytes(int ccID) { return ConnectionInfos.get(ccID).CCmaxbytes; }
	public long getBytes(int ccID) { return ConnectionInfos.get(ccID).CCbytes; }
	public int getState(int ccID) { return ConnectionInfos.get(ccID).CCstate; }
	public String getInfo(int ccID) { return ConnectionInfos.get(ccID).CCinfo; }
	public long getBPS(int ccID) { return ConnectionInfos.get(ccID).CCbps; }


	//::Useful data which other classes can set:
	public void setNick(int ccID, String s) { ConnectionInfos.get(ccID).CCnick = s; }
	public void setFile(int ccID, String s) { ConnectionInfos.get(ccID).CCfile = s; }
	public void setIP(int ccID, String s) {ConnectionInfos.get(ccID).CCip = s; }
	public void setPort(int ccID, int i) { ConnectionInfos.get(ccID).CCport = i; }
	public void setDirection(int ccID, int i) {ConnectionInfos.get(ccID).CCDirection = i; }
	public void setlistIndex(int ccID, int i) { ConnectionInfos.get(ccID).CClistIndex = i; }
	public void setMaxBytes(int ccID, long l) { ConnectionInfos.get(ccID).CCmaxbytes = l; }
	public void setBytes(int ccID, long l) { ConnectionInfos.get(ccID).CCbytes = l; }
	synchronized public void setState(int ccID, int i) { ConnectionInfos.get(ccID).CCstate = i; }
	public void setInfo(int ccID, String s) { ConnectionInfos.get(ccID).CCinfo = s; }

	//::Update view
    public void UpdateStatus(int ccID)
    {

		if(getState(ccID) == C_ing) {
			setInfo(ccID, "Connecting...");
		} else if(getState(ccID) == RSing) {
			setInfo(ccID, "Started Resume...");
		} else if(getState(ccID) == DLoad) {
			setInfo(ccID, "Download Started...");
		} else if(getState(ccID) == ULoad) {
			setInfo(ccID, "Upload Started...");
		} else if(getState(ccID) == Waita) {
			setInfo(ccID, "Transfer Finished! Idle...");
		} else if(getState(ccID) == Finit) {
			setInfo(ccID, "Transfer Finished!");
		} else if(getState(ccID) == Not_C) {
			setInfo(ccID, "Connection Closed");
		}
		
    }

    //Update View for Abort
    public void setAbort(int ccID, String s)
    {
		ConnectionInfos.get(ccID).CCstate = Abort;
		ConnectionInfos.get(ccID).CCinfo = s;
		
    }

}